
package operations;
import java.io.Serializable;



public class OperationResult extends OperationInformation {

	private static final long serialVersionUID = 772248461493438644L;

	public static final String KEY = "OP_RESULT";

	public static enum Status {
		/** The operation has not been executed */
		NOT_EXECUTED,

		/** the operation is invalid */
		PRECONDITION_ERROR,

		/** the operation is faulty */
		POSTCONDITION_ERROR,

		/** the operation is OK: it terminates without throwing any exception */
		SUCCESSFUL,

		/** the operation is OK: it terminates throwing an exception */
		EXCEPTIONAL
	}

	protected Status status = Status.NOT_EXECUTED;
	protected String excClassName = null;
	protected String excMessage = null;
	
	protected Value object = null;
	protected Value result = null;

	public OperationResult() {
		super(KEY);
	}

	private OperationResult(OperationResult other)  {
		super(KEY);

		status = other.status;
		excClassName = other.excClassName;
		excMessage = other.excMessage;
	}
	public void setSuccessful(Object object, Object result)  {
		status = Status.SUCCESSFUL;
		this.object = new Value(null);
		this.result = new Value(null);

	}

	/**
	 * Sets the status of the operation as precondition error
	 * @throws ReplayException during a replay, this operation signals a different behavior of the class
	 */
	public void setPreconditionError()  {
		status = Status.PRECONDITION_ERROR;
	}

	/**
	 * Sets the status of the operation as postcondition error
	 * @throws ReplayException during a replay, this operation signals a different behavior of the class
	 */
	public void setPostconditionError()  {
		status = Status.POSTCONDITION_ERROR;
	}

	public void setExceptional(Throwable exc, Object object)  {
		status = Status.EXCEPTIONAL;
		excClassName = exc.getClass().getName();
		excMessage = exc.getMessage();
		this.object = new Value(object);
	}


	public Status getStatus() {
		return status;
	}


	public String getExcClassName() {
		return excClassName;
	}

	public String getExcMessage() {
		return excMessage;
	}


	@Override
	public OperationInformation clone() {
		return new OperationResult(this);
	}

	@Override
	public String toString() {
		if(status == Status.NOT_EXECUTED) return "Not Executed";

		String ret = status.toString();
		if(status == Status.EXCEPTIONAL) ret += " " + excClassName + ": " + excMessage + ";";
//		if(object != null) ret += " object: " + object + ";";
//		if(result != null) ret += " result: " + result + ";";
		return ret;
	}
	public static final class Value implements Serializable {
		private static final long serialVersionUID = -100047631209369725L;

		private final boolean isNull;
		private final String type;
		private final Serializable object;

		public Value(Object o) {
			if(o == null) {
				isNull = true;
				type = null;
				object = null;
			} else {
				isNull = false;
				type = o.getClass().getName();
				object = saveObject(o);				
			}
		}
		private static Serializable saveObject(Object o) {
			if(o == null) return null;

			Class<?> c = o.getClass();
			if(c == Boolean.TYPE || c == Boolean.class ||
					c == Byte.TYPE || c == Byte.class ||
					c == Character.TYPE || c == Character.class || c == String.class ||
					c == Short.TYPE || c == Short.class ||
					c == Integer.TYPE || c == Integer.class ||
					c == Long.TYPE || c == Long.class ||
					c == Float.TYPE || c == Float.class ||
					c == Double.TYPE || c == Double.class)
				return (Serializable) o;
			return null;
		}
		@Override
		public String toString() {
			if(isNull) return "null";
			StringBuilder sb = new StringBuilder();
			if(type != null) sb.append("type:").append(type);
			if(object != null) sb.append(" object:").append(object);
			return sb.toString();
		}

	}//class Value

}
